package graph
import (
"fmt"
"github.com/K-Phoen/grabana/alert"
"github.com/K-Phoen/grabana/axis"
"github.com/K-Phoen/grabana/errors"
"github.com/K-Phoen/grabana/graph/series"
"github.com/K-Phoen/grabana/links"
"github.com/K-Phoen/grabana/target/graphite"
"github.com/K-Phoen/grabana/target/influxdb"
"github.com/K-Phoen/grabana/target/prometheus"
"github.com/K-Phoen/grabana/target/stackdriver"
"github.com/K-Phoen/sdk"
)
type Option func (graph *Graph ) error
type DrawMode uint8
const (
Bars DrawMode = iota
Lines
Points
)
type NullValue string
const (
AsZero NullValue = "null as zero"
AsNull NullValue = "null"
Connected NullValue = "connected"
)
type LegendOption uint16
const (
Hide LegendOption = iota
AsTable
ToTheRight
Min
Max
Avg
Current
Total
NoNullSeries
NoZeroSeries
)
type Graph struct {
Builder *sdk .Panel
Alert *alert .Alert
}
func New (title string , options ...Option ) (*Graph , error ) {
panel := &Graph {Builder : sdk .NewGraph (title )}
panel .Builder .AliasColors = make (map [string ]interface {})
panel .Builder .IsNew = false
panel .Builder .GraphPanel .Tooltip .Sort = 2
panel .Builder .GraphPanel .Tooltip .Shared = true
for _ , opt := range append (defaults (), options ...) {
if err := opt (panel ); err != nil {
return nil , err
}
}
return panel , nil
}
func defaults() []Option {
return []Option {
Draw (Lines ),
Span (6 ),
Fill (1 ),
Null (AsZero ),
LineWidth (1 ),
Legend (NoZeroSeries , NoNullSeries ),
defaultAxes (),
}
}
func defaultAxes() Option {
return func (graph *Graph ) error {
graph .Builder .GraphPanel .YAxis = true
graph .Builder .GraphPanel .XAxis = true
graph .Builder .GraphPanel .Yaxes = []sdk .Axis {
*axis .New ().Builder ,
*axis .New (axis .Hide ()).Builder ,
}
graph .Builder .GraphPanel .Xaxis = *axis .New (axis .Unit ("time" )).Builder
return nil
}
}
func Links (panelLinks ...links .Link ) Option {
return func (graph *Graph ) error {
graph .Builder .Links = make ([]sdk .Link , 0 , len (panelLinks ))
for _ , link := range panelLinks {
graph .Builder .Links = append (graph .Builder .Links , link .Builder )
}
return nil
}
}
func WithPrometheusTarget (query string , options ...prometheus .Option ) Option {
target := prometheus .New (query , options ...)
return func (graph *Graph ) error {
graph .Builder .AddTarget (&sdk .Target {
RefID : target .Ref ,
Hide : target .Hidden ,
Expr : target .Expr ,
IntervalFactor : target .IntervalFactor ,
Interval : target .Interval ,
Step : target .Step ,
LegendFormat : target .LegendFormat ,
Instant : target .Instant ,
Format : target .Format ,
})
return nil
}
}
func WithGraphiteTarget (query string , options ...graphite .Option ) Option {
target := graphite .New (query , options ...)
return func (graph *Graph ) error {
graph .Builder .AddTarget (target .Builder )
return nil
}
}
func WithInfluxDBTarget (query string , options ...influxdb .Option ) Option {
target := influxdb .New (query , options ...)
return func (graph *Graph ) error {
graph .Builder .AddTarget (target .Builder )
return nil
}
}
func WithStackdriverTarget (target *stackdriver .Stackdriver ) Option {
return func (graph *Graph ) error {
graph .Builder .AddTarget (target .Builder )
return nil
}
}
func DataSource (source string ) Option {
return func (graph *Graph ) error {
graph .Builder .Datasource = &sdk .DatasourceRef {LegacyName : source }
return nil
}
}
func Span (span float32 ) Option {
return func (graph *Graph ) error {
if span < 1 || span > 12 {
return fmt .Errorf ("span must be between 1 and 12: %w" , errors .ErrInvalidArgument )
}
graph .Builder .Span = span
return nil
}
}
func Height (height string ) Option {
return func (graph *Graph ) error {
graph .Builder .Height = &height
return nil
}
}
func Description (content string ) Option {
return func (graph *Graph ) error {
graph .Builder .Description = &content
return nil
}
}
func Transparent () Option {
return func (graph *Graph ) error {
graph .Builder .Transparent = true
return nil
}
}
func LeftYAxis (opts ...axis .Option ) Option {
return func (graph *Graph ) error {
graph .Builder .GraphPanel .Yaxes [0 ] = *axis .New (opts ...).Builder
return nil
}
}
func RightYAxis (opts ...axis .Option ) Option {
return func (graph *Graph ) error {
graph .Builder .GraphPanel .Yaxes [1 ] = *axis .New (opts ...).Builder
return nil
}
}
func XAxis (opts ...axis .Option ) Option {
return func (graph *Graph ) error {
graph .Builder .GraphPanel .Xaxis = *axis .New (opts ...).Builder
return nil
}
}
func Alert (name string , opts ...alert .Option ) Option {
return func (graph *Graph ) error {
graph .Alert = alert .New (graph .Builder .Title , append (opts , alert .Summary (name ))...)
graph .Alert .Builder .Name = graph .Builder .Title
return nil
}
}
func Draw (modes ...DrawMode ) Option {
return func (graph *Graph ) error {
graph .Builder .Bars = false
graph .Builder .Lines = false
graph .Builder .Points = false
for _ , mode := range modes {
switch mode {
case Bars :
graph .Builder .Bars = true
case Lines :
graph .Builder .Lines = true
case Points :
graph .Builder .Points = true
default :
return errors .ErrInvalidArgument
}
}
return nil
}
}
func Fill (value int ) Option {
return func (graph *Graph ) error {
if value < 0 || value > 10 {
return fmt .Errorf ("fill must be between 0 and 10: %w" , errors .ErrInvalidArgument )
}
graph .Builder .Fill = value
return nil
}
}
func LineWidth (value uint ) Option {
return func (graph *Graph ) error {
if value > 10 {
return fmt .Errorf ("line width must be between 0 and 10: %w" , errors .ErrInvalidArgument )
}
graph .Builder .Linewidth = value
return nil
}
}
func Staircase () Option {
return func (graph *Graph ) error {
graph .Builder .GraphPanel .SteppedLine = true
return nil
}
}
func PointRadius (value float32 ) Option {
return func (graph *Graph ) error {
if value < 0 || value > 10 {
return fmt .Errorf ("point radius must be between 0 and 10: %w" , errors .ErrInvalidArgument )
}
graph .Builder .Pointradius = value
return nil
}
}
func Null (mode NullValue ) Option {
return func (graph *Graph ) error {
graph .Builder .GraphPanel .NullPointMode = string (mode )
return nil
}
}
func Repeat (repeat string ) Option {
return func (graph *Graph ) error {
graph .Builder .Repeat = &repeat
return nil
}
}
func RepeatDirection (direction sdk .RepeatDirection ) Option {
return func (graph *Graph ) error {
graph .Builder .RepeatDirection = &direction
return nil
}
}
func SeriesOverride (opts ...series .OverrideOption ) Option {
return func (graph *Graph ) error {
override := sdk .SeriesOverride {}
for _ , opt := range opts {
if err := opt (&override ); err != nil {
return err
}
}
graph .Builder .GraphPanel .SeriesOverrides = append (graph .Builder .GraphPanel .SeriesOverrides , override )
return nil
}
}
func Legend (opts ...LegendOption ) Option {
return func (graph *Graph ) error {
legend := sdk .Legend {Show : true }
for _ , opt := range opts {
switch opt {
case Hide :
legend .Show = false
case AsTable :
legend .AlignAsTable = true
case ToTheRight :
legend .RightSide = true
case Min :
legend .Min = true
legend .Values = true
case Max :
legend .Max = true
legend .Values = true
case Avg :
legend .Avg = true
legend .Values = true
case Current :
legend .Current = true
legend .Values = true
case Total :
legend .Total = true
legend .Values = true
case NoNullSeries :
legend .HideEmpty = true
case NoZeroSeries :
legend .HideZero = true
default :
return errors .ErrInvalidArgument
}
}
graph .Builder .GraphPanel .Legend = legend
return nil
}
}
The pages are generated with Golds v0.8.2 . (GOOS=linux GOARCH=amd64)
Golds is a Go 101 project developed by Tapir Liu .
PR and bug reports are welcome and can be submitted to the issue list .
Please follow @zigo_101 (reachable from the left QR code) to get the latest news of Golds .